<?php declare(strict_types=1);

/**
 * @author      guosir
 * @copyright   2023-2025 owner
 **/

namespace Srv\Apps\Apis\User\Ctl;

use Srv\Apps\Apis\Admin\Ctl\AdminCtl;
use Srv\Apps\Apis\Common\DefCtl\DefLogoutCtl;
use Srv\Apps\Apis\Common\IdxCtl\IdxIp;
use Srv\Apps\Proto\DTO\User\LogoutListDTO;
use Srv\Apps\Proto\Enum\Common\LogoutStatusEnum;
use Srv\Apps\Proto\Enum\YesOrNoEnum;
use Srv\Apps\Proto\VO\Admin\AdmUserInfoBasicVO;
use Srv\Apps\Proto\VO\User\LogoutListVO;
use Srv\Apps\Proto\VO\User\LogoutVO;
use Srv\Apps\Proto\VO\User\UserInfoBasicVO;
use Srv\Libs\Common\CommArray;
use Srv\Libs\Common\CommTime;
use Srv\Libs\Frame\AuthData;
use Srv\Libs\Frame\ControllerAbstract;
use Srv\Libs\Frame\Page;
use Srv\Libs\Storage\DataMysql;
use Srv\Libs\Tools\IpAddr;

final class LogoutCtl extends ControllerAbstract
{
    private ?DataMysql $DbAuto              = null;     // DB-Write
    private int $logoutTime                 = 86400;        // 审核通过后可注销时长[秒]

    /**
     * @return static
     * tag
     */
    final public static function tag():self
    {
        $thisObject                         = self::tagGet();
        if($thisObject instanceof self){
            $thisObject->DbAuto             = self::getDbAuto();
        }
        return $thisObject;
    }

    /**
     * @param Page $Page
     * @param array $whereData
     * @return LogoutListVO|null
     * getLogoutList
     */
    public function getLogoutList(Page $Page, array $whereData):?LogoutListVO
    {
        $limitString        = $Page->getLimitString();
        $whereString        = ' WHERE ultr_delete=0 ';
        $whereInfoString    = ' WHERE usi_delete=0';
        $infoSearch         = false;
        // 检索条件
        if(count($whereData) > 0) foreach ($whereData as $key => $val){
            switch ($key){
                case LogoutListDTO::_userId:
                    $whereString        .= (strlen($whereString)>0?' AND ':'').'user_id='. intval($val);
                    break;
                case LogoutListDTO::_nickname:
                    $infoSearch         = true;
                    $whereInfoString    .= (strlen($whereInfoString)>0?' AND ':'').'usi_nickname LIKE \'%'.$this->DbAuto->getRealEscapeString($val).'%\'';
                    break;
                case LogoutListDTO::_idNum:
                    if(strlen($val) > 10 && is_numeric($val)){
                        $whereString        .= (strlen($whereString)>0?' AND ':'').'user_id='. intval($val);
                    }else{
                        $infoSearch         = true;
                        $whereInfoString    .= (strlen($whereInfoString)>0?' AND ':'').'usi_idnum LIKE \'%'.$this->DbAuto->getRealEscapeString($val).'%\'';
                    }
                    break;
                case LogoutListDTO::_admUserId:
                    $whereString        .= (strlen($whereString)>0?' AND ':'').'auir_id='. intval($val);
                    break;
                case LogoutListDTO::_review:
                    $whereString        .= (strlen($whereString)>0?' AND ':'').'ultr_review='. intval($val);
                    break;
                case LogoutListDTO::_createTimeStart:
                    $whereString        .= (strlen($whereString)>0?' AND ':'').'ultr_create_time>='. intval($val);
                    break;
                case LogoutListDTO::_createTimeStop:
                    $whereString        .= (strlen($whereString)>0?' AND ':'').'ultr_create_time<='. intval($val);
                    break;
            }
        }
        if($infoSearch){
            $subSql         = 'SELECT user_id FROM '.$this->DbAuto->getTableNameAll('user_info').$whereInfoString;
            $whereString    .=  (strlen($whereString)>0?' AND ':'').'user_id IN('.$subSql.')';
        }
        $isFail             = false;
        $sql                = 'SELECT SQL_CALC_FOUND_ROWS ultr_id, user_id, lott_id, ultr_apply_ip, ultr_review_allow_time, ultr_review, ultr_review_time, auir_id, ultr_review_remark, ultr_review_ip, ultr_logout_allow_time, ultr_logout_data, ultr_create_time, ultr_update_time FROM '.$this->DbAuto->getTableNameAll('user_logout_record').$whereString.' ORDER BY ultr_id DESC '.$limitString;
        $list               = $this->DbAuto->getData($sql, $isFail);
        $totalNum           = $this->DbAuto->getDataInt('SELECT FOUND_ROWS() as num', 'num');
        if($isFail) return null;
        $LogoutVOList       = [];
        if(CommArray::isForeach($list)){
            $UserCtl                = UserCtl::tag();
            $userIdList             = array_unique(array_filter(array_map('intval', array_column($list, 'user_id'))));
            $admUserIdList          = array_unique(array_filter(array_map('intval', array_column($list, 'auir_id'))));
            $UserInfoBasicVOList    = $UserCtl->getUserInfoBasicBatch($userIdList);
            $AdmUserBasicVOList     = AdminCtl::tag()->getAdmUserInfoBasicBatch($admUserIdList);
            foreach($list as $item){
                $ultrIdItem         = intval($item['ultr_id']??0);
                if($ultrIdItem < 1) continue;
                $userIdItem         = intval($item['user_id']);
                if($userIdItem < 1) continue;
                $LogoutVO           = $this->getLogoutVO($item);
                if(!($LogoutVO instanceof LogoutVO)) continue;
                $UserInfoBasicVO    = $UserInfoBasicVOList[$userIdItem]??null;
                if(!($UserInfoBasicVO instanceof UserInfoBasicVO)) continue;
                $LogoutVO->setUserInfoBasic($UserInfoBasicVO);
                $admUserIdItem      = intval($item['auir_id']);
                $AdmUserInfoBasicVO = $AdmUserBasicVOList[$admUserIdItem]??null;
                if($AdmUserInfoBasicVO instanceof AdmUserInfoBasicVO) $LogoutVO->setAdmUserBasic($AdmUserInfoBasicVO);
                $LogoutVOList[]     = $LogoutVO;
            }
        }
        $LogoutListVO               = new LogoutListVO();
        $LogoutListVO->setList($LogoutVOList);
        $LogoutListVO->setPage($Page->getPageVO($totalNum));
        return $LogoutListVO;
    }

    /**
     * @param array $info
     * @return LogoutVO|null
     * getLogoutVO
     */
    public function getLogoutVO(array $info):?LogoutVO{
        $ultrId             = intval($info['ultr_id']??0);
        if($ultrId < 1) return null;
        $currTime           = CommTime::getTimeStamp();
        $LogoutVO           = new LogoutVO();
        $LogoutVO->setUltrId($ultrId);
        $LogoutVO->setUserId(intval($info['user_id']));
        $LogoutVO->setLogoutType(DefLogoutCtl::tag()->getExtStrById(intval($info['lott_id']), DefLogoutCtl::EXT_NAME));
        $applyIpString      = IdxIp::tag()->getIpStrByInt(intval($info['ultr_apply_ip']));
        $applyArea          = IpAddr::getLocationInfo($applyIpString);
        $LogoutVO->setApplyIp($applyIpString.'('.($applyArea['country']??'').')');
        $reviewAllowTime    = intval($info['ultr_review_allow_time']);
        $LogoutVO->setReviewAllowTime($reviewAllowTime);
        $review             = LogoutStatusEnum::parseValue($info['ultr_review']);
        $isReview           = $review === LogoutStatusEnum::LOGOUT_STATUS_APPLY && $currTime>=$reviewAllowTime?YesOrNoEnum::YES_OR_NO_YES:YesOrNoEnum::YES_OR_NO_NO;
        $LogoutVO->setIsReview($isReview);
        $LogoutVO->setReview($review);
        $LogoutVO->setReviewTime(intval($info['ultr_review_time']));
        $LogoutVO->setReviewRemark(trim($info['ultr_review_remark']));
        $LogoutVO->setReviewIp(IdxIp::tag()->getIpStrByInt(intval($info['ultr_review_ip'])));
        $LogoutVO->setLogoutAllowTime(intval($info['ultr_logout_allow_time']));
        $LogoutVO->setLogoutData(trim($info['ultr_logout_data']));
        $LogoutVO->setCreateTime(intval($info['ultr_create_time']));
        $LogoutVO->setUpdateTime(intval($info['ultr_update_time']));
        return $LogoutVO;
    }

    /**
     * @param array $utlrIdList
     * @param int $review
     * @param string $reviewRemark
     * @return bool
     * setLogoutReview
     */
    public function setLogoutReview(array $utlrIdList, int $review, string $reviewRemark):bool
    {
        if(count($utlrIdList) < 1 || !in_array($review, [0, 1], true)) return false;
        $currTime           = CommTime::getTimeStamp();
        $ipIntStr           = IdxIp::tag()->getReqIpNumStr();
        $admUserId          = AuthData::getLoginUserId();
        $logoutAllowTime    = $currTime + 86400;
        if($review === YesOrNoEnum::YES_OR_NO_YES){
            $sql            = 'UPDATE '.$this->DbAuto->getTableNameAll('user_logout_record').' SET ultr_review='.LogoutStatusEnum::LOGOUT_STATUS_ACCEPT.', ultr_update_time='.$currTime.', ultr_review_time='.$currTime.', ultr_review_ip='.$ipIntStr.', auir_id='.$admUserId.', ultr_logout_allow_time='.$logoutAllowTime.', ultr_review_remark=\''.$this->DbAuto->getRealEscapeString($reviewRemark).'\' WHERE ultr_id IN('.implode(',', $utlrIdList).') AND ultr_review='.LogoutStatusEnum::LOGOUT_STATUS_APPLY.' AND ultr_delete=0 AND ultr_review_allow_time<='.$currTime;
        }else{
            $sql            = 'UPDATE '.$this->DbAuto->getTableNameAll('user_logout_record').' SET ultr_review='.LogoutStatusEnum::LOGOUT_STATUS_REJECT.', ultr_update_time='.$currTime.', ultr_review_time='.$currTime.', ultr_review_ip='.$ipIntStr.', auir_id='.$admUserId.', ultr_review_remark=\''.$this->DbAuto->getRealEscapeString($reviewRemark).'\' WHERE ultr_id IN('.implode(',', $utlrIdList).') AND ultr_review='.LogoutStatusEnum::LOGOUT_STATUS_APPLY.' AND ultr_delete=0 AND ultr_review_allow_time<='.$currTime;
        }
        return $this->DbAuto->getDataNum($sql)>0;
    }

    /**
     * @param array $utlrIdList
     * @return bool
     * checkReviewStatus
     */
    public function checkReviewStatus(array $utlrIdList):bool
    {
        $ultrIdListSize = count($utlrIdList);
        if($ultrIdListSize < 1) return false;
        $currTime   = CommTime::getTimeStamp();
        $sql        = 'SELECT COUNT(ultr_id) AS num FROM '.$this->DbAuto->getTableNameAll('user_logout_record').' WHERE ultr_id IN('.implode(',', $utlrIdList).') AND ultr_delete=0 AND ultr_review='.LogoutStatusEnum::LOGOUT_STATUS_APPLY.' AND ultr_review_allow_time<='.$currTime;
        $num        = $this->DbAuto->getDataInt($sql, 'num');
        if($num !== $ultrIdListSize) return false;
        return true;
    }
}